﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Kokomo.Mirror.Ia32
{
	public struct OpCode
	{
		static OpCode()
		{
			_emptyOperandTypes = new OperandType[0];
		}

		private static OperandType[] _emptyOperandTypes;

		internal OpCode(
			int value,
			int length,
			OpCodeForm form,
			Mnemonic mnemonic,
			params OperandType[] operandTypes
			)
			: this()
		{
			this.Value = value;
			this.Length = length;
			this.Mnemonic = mnemonic;

			// Validate operands
			bool needsModRM = false;
			foreach (var operandType in operandTypes)
			{
				OperandType encoding = operandType & OperandType.EncodingMask;
				needsModRM =
					(encoding == OperandType.ModRM)
					|| (encoding == OperandType.Reg)
					;
				if (needsModRM) break;
			}

			bool hasModRM = form == OpCodeForm.ModRM;
			if (needsModRM && !hasModRM)
			{
				//throw new ArgumentException("The operand types require ModR/M, but Form does not indicate it");
				form = OpCodeForm.ModRM;
				hasModRM = true;
			}
			else if (hasModRM && !needsModRM)
			{
				form = OpCodeForm.Normal;
			}

			this.Form = form;

			this.OperandTypes = operandTypes;
		}

		public bool IsUnknown { get { return this.Length == 0; } }

		public int Value { get; private set; }
		public int Length { get; private set; }
		public OpCodeForm Form { get; private set; }
		public Mnemonic Mnemonic { get; private set; }
		public OperandType[] OperandTypes { get; private set; }

		public Prefixes PrefixCode { get; private set; }
		public Prefixes MandatoryPrefixes { get; internal set; }

		public override string ToString()
		{
			return this.Mnemonic.ToString();
		}
	}
}
